package app.tvprogram;

import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.rmi.RemoteException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;


public class TvProgramManager {
    private final static Map<Integer, String> areaMap = new HashMap<Integer, String>(
            40);
    private final static Map<Integer, String> tvStationMap = new HashMap<Integer, String>(
            200);
    private final static Map<Integer, String> tvChannelMap = new HashMap<Integer, String>(
            1000);
    @Deprecated
    private final static Map<Integer, TvProgram> tvProgramMap = new HashMap<Integer, TvProgram>();
    private final static String DATADIR = "xmldata";
    private final static String DATAFILE = DATADIR + File.separatorChar
            + "data.xml";
    private final static String FAVORITEFILE = DATADIR + File.separatorChar
            + "favorite.xml";
    private final static String TEMPDATAFILE = DATADIR + File.separatorChar
            + "temp.xml";

    private final static int[] availableTvStationIdArray = new int[] { 208, 3,
            39, 41, 42, 2 };
    private final static int[][] availableTvChannelIdArray = new int[][] {
            new int[] { 689, 690, 691, 692, 693, 694, 695, 698, 700, 702, 703,
                    704, 706, 708, 712, 714, 717, 718 },
            new int[] { 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638,
                    639, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650,
                    651, 652, 653, 654, 655, 656, 657, 658, 659, 660 },
            new int[] { 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616,
                    617, 618, 619, 620, 621, 622 }, new int[] { 623 },
            new int[] { 624, 625, 626, 627 },
            new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } };
    private final static int[][] defaultFavoriteTvChannelIdArray = new int[][] {
            new int[] { 689, 690, 691, 693, 695, 698, 700, 703, 704, 706, 708,
                    712, 714, 717 }, new int[] { 629, 639, 641 },
            new int[] { 606, 607, 608, 612, 613, 614, 615, 616, 617, 619 },
            new int[] { 623 }, new int[] {},
            new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 } };
    private static Set<Integer> userFavoriteTvChannelIdSet = new HashSet<Integer>();
    private final static Map<Integer, String> availableTvStationMap = new HashMap<Integer, String>(
            30);
    private final static Map<Integer, String> availableTvChannelMap = new HashMap<Integer, String>(
            100);
    private final static Map<Integer, String> favoriteTvChannelMap = new HashMap<Integer, String>(
            80);
    private final static Map<Integer, TvProgram> availableTvProgramMap = new HashMap<Integer, TvProgram>(
            1500);

    private static TvProgramManager instance;

    public static TvProgramManager getInstance() {
        if (instance == null) {
            instance = new TvProgramManager();
        }
        return instance;
    }

    private TvProgramManager() {
        this.init();
    }

    private void init() {
        System.out.println("TvProgramManager.init start...");
        File file = new File(DATAFILE);
        if (file.exists()) {
            System.out.println("local data file exists");
            this.readBasicDataFromLocal();
        } else {
            this.fetchBasicDataFromServer();
            this.persistBasicDataToLocal();
        }
        file = new File(FAVORITEFILE);
        if (file.exists()) {
            System.out.println("local favorite file exists");
            this.readFavoriteFromLocal();
        }
        this.initAvailableAndFavoriteBasicData();
        System.out.println("TvProgramManager.init end");
    }

    private void fetchBasicDataFromServer() {
        System.out
                .println("TvProgramManager.fetchBasicDataFromServer start...");
        try {
            TvProgramWsClient client = new TvProgramWsClient();
            String[] areaArray = client
                    .invoke("getAreaString", new Object[] {});
            String[] tvStationArray = null;
            String[] tvChannelArray = null;
            System.out.println("Area list : " + Arrays.asList(areaArray));
            if (areaArray == null) {
                return;
            }
            for (String area : areaArray) {
                String[] tokens = area.split("@");
                int areaId = Integer.valueOf(tokens[0]);
                areaMap.put(areaId, tokens[1]);
                tvStationArray = client.invoke("getTVstationString",
                        new Object[] { areaId });
                System.out.println("TvStation list : "
                        + Arrays.asList(tvStationArray));
                if (tvStationArray == null) {
                    continue;
                }
                for (String tvStation : tvStationArray) {
                    tokens = tvStation.split("@");
                    int tvStationId = Integer.valueOf(tokens[0]);
                    tvStationMap.put(tvStationId, tokens[1]);
                    tvChannelArray = client.invoke("getTVchannelString",
                            new Object[] { tvStationId });
                    System.out.println("TvChannel list : "
                            + Arrays.asList(tvChannelArray));
                    if (tvChannelArray == null) {
                        continue;
                    }
                    for (String tvChannel : tvChannelArray) {
                        tokens = tvChannel.split("@");
                        int tvChannelId = Integer.valueOf(tokens[0]);
                        tvChannelMap.put(tvChannelId, tokens[1]);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            this.deleteBasicDataFromLocal();
        }
        System.out.println("TvProgramManager.fetchBasicDataFromServer end");
    }

    private void persistBasicDataToLocal() {
        System.out.println("TvProgramManager.persistBasicDataToLocal start...");
        if (areaMap.size() > 0 && tvStationMap.size() > 0
                && tvChannelMap.size() > 0) {
            try {
                XMLEncoder xe = new XMLEncoder(new BufferedOutputStream(
                        new FileOutputStream(DATAFILE)));
                xe.writeObject(areaMap);
                xe.flush();
                xe.writeObject(tvStationMap);
                xe.flush();
                xe.writeObject(tvChannelMap);
                xe.flush();
                // xe.writeObject(tvProgramMap);
                xe.close();
            } catch (Exception e) {
                e.printStackTrace();
                this.deleteBasicDataFromLocal();
            }
        } else {
            System.out.println("areaMap.size()=" + areaMap.size()
                    + ",tvStationMap.size()" + tvStationMap.size()
                    + ",tvChannelMap.size()" + tvChannelMap.size());
        }
        System.out.println("TvProgramManager.persistBasicDataToLocal end");
    }

    private void readBasicDataFromLocal() {
        System.out.println("TvProgramManager.readBasicDataFromLocal start...");
        try {
            XMLDecoder xd = new XMLDecoder(new BufferedInputStream(
                    new FileInputStream(DATAFILE)));
            areaMap.putAll((Map) xd.readObject());
            System.out.println("areaMap(" + areaMap.size() + ") : " + areaMap);
            tvStationMap.putAll((Map) xd.readObject());
            System.out.println("tvStationMap(" + tvStationMap.size() + ") : "
                    + tvStationMap);
            tvChannelMap.putAll((Map) xd.readObject());
            // for (String str : tvChannelMap.values()) {
            // System.out.println(str);
            // }
            System.out.println("tvChannelMap(" + tvChannelMap.size() + ") : "
                    + tvChannelMap);
            // tvProgramMap.putAll((Map) xd.readObject());
            // System.out.println(tvProgramMap);
            xd.close();
        } catch (Exception e) {
            e.printStackTrace();
            this.deleteBasicDataFromLocal();
        }
        System.out.println("TvProgramManager.readBasicDataFromLocal end");
    }

    private void deleteBasicDataFromLocal() {
        System.out
                .println("TvProgramManager.deleteBasicDataFromLocal start...");
        File file = new File(DATAFILE);
        if (file.exists()) {
            file.delete();
        }
        System.out.println("TvProgramManager.deleteBasicDataFromLocal end");
    }

    private void readFavoriteFromLocal() {
        System.out
                .println("TvProgramManager.readFavoriteDataFromLocal start...");
        try {
            XMLDecoder xd = new XMLDecoder(new BufferedInputStream(
                    new FileInputStream(FAVORITEFILE)));
            userFavoriteTvChannelIdSet = (Set) xd.readObject();
            xd.close();
        } catch (Exception e) {
            e.printStackTrace();
            this.deleteFavoriteFromLocal();
        }
        System.out.println("TvProgramManager.readFavoriteDataFromLocal end");
    }

    private void deleteFavoriteFromLocal() {
        System.out.println("TvProgramManager.deleteFavoriteFromLocal start...");
        File file = new File(FAVORITEFILE);
        if (file.exists()) {
            file.delete();
        }
        System.out.println("TvProgramManager.deleteFavoriteFromLocal end");
    }

    private void initAvailableAndFavoriteBasicData() {
        System.out
                .println("TvProgramManager.initAvailableAndFavoriteBasicData start...");
        try {
            for (int tvStationId : availableTvStationIdArray) {
                availableTvStationMap.put(tvStationId,
                        tvStationMap.get(tvStationId));
            }
            System.out.println("availableTvStationMap("
                    + availableTvStationMap.size() + ")"
                    + availableTvStationMap);
            for (int[] tvChannelIdArray : availableTvChannelIdArray) {
                for (int tvChannelId : tvChannelIdArray) {
                    availableTvChannelMap.put(tvChannelId,
                            tvChannelMap.get(tvChannelId));
                }
            }
            System.out.println("availableTvChannelMap("
                    + availableTvChannelMap.size() + ")"
                    + availableTvChannelMap);
            if (userFavoriteTvChannelIdSet.size() > 0) {
                for (int tvChannelId : userFavoriteTvChannelIdSet) {
                    favoriteTvChannelMap.put(tvChannelId,
                            tvChannelMap.get(tvChannelId));
                }
            } else {
                for (int[] tvChannelIdArray : defaultFavoriteTvChannelIdArray) {
                    for (int tvChannelId : tvChannelIdArray) {
                        favoriteTvChannelMap.put(tvChannelId,
                                tvChannelMap.get(tvChannelId));
                    }
                }
            }
            System.out.println("favoriteTvChannelMap("
                    + favoriteTvChannelMap.size() + ")" + favoriteTvChannelMap);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out
                .println("TvProgramManager.initAvailableAndFavoriteBasicData end");
    }

    public void initTvProgram(Map<Integer, String> tvChannelMap,
            boolean fromLocal, boolean reInitTempDataFile) {
        System.out.println("TvProgramManager.initTvProgram start...");
        if (tvChannelMap != null && tvChannelMap.size() > 0) {
            try {
                File file = new File(TEMPDATAFILE);
                if (file.exists() && fromLocal) {
                    System.out.println("local temp file exists");
                    System.out
                            .println("read program data from local temp file");
                    XMLDecoder xd = new XMLDecoder(new BufferedInputStream(
                            new FileInputStream(TEMPDATAFILE)));
                    availableTvProgramMap.putAll((Map) xd.readObject());
                    xd.close();
                } else {
                    initTvProgramFromFromServer(tvChannelMap,
                            reInitTempDataFile);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("availableTvProgramMap("
                    + availableTvProgramMap.size() + ") : "
                    + availableTvProgramMap);
        } else {
            System.out.println("tvChannelMap is empty");
        }
        System.out.println("TvProgramManager.initTvProgram end");
    }

    private void initTvProgramFromFromServer(Map<Integer, String> tvChannelMap,
            boolean reInitTempDataFile) throws RemoteException,
            FileNotFoundException {
        System.out.println("fetch program data from server");
        TvProgramWsClient client = new TvProgramWsClient();
        String[] tvProgramArray = null;
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.SECOND, 0);
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        String dateStr = df.format(cal.getTime());
        System.out.println("dateStr=" + dateStr);
        for (int tvChannelId : tvChannelMap.keySet()) {
            tvProgramArray = client.invoke("getTVprogramString", new Object[] {
                    tvChannelId, dateStr, null });
            System.out.println("TvProgram list : "
                    + Arrays.asList(tvProgramArray));
            if (tvProgramArray == null) {
                continue;
            }
            int tmpId = -1;
            for (Integer i = 0; i < tvProgramArray.length; i++) {
                if (tvProgramArray[i].startsWith("(-")) {
                    continue;
                }
                String[] tokens = tvProgramArray[i].split("@");
                TvProgram tp = new TvProgram();
                tp.setTvChannelId(tvChannelId);
                tp.setTvChannelName(availableTvChannelMap.get(tvChannelId));
                tp.setId(tvChannelId * 100 + i);
                tp.setName(tokens[3]);
                String time = tokens[0];
                if (!time.startsWith("(-")) {
                    int hour = Integer.valueOf(time.substring(0, 2));
                    int minute = Integer.valueOf(time.substring(3, 5));
                    String ampm = time.substring(6, 8);
                    if ("PM".equals(ampm)) {
                        hour += 12;
                    }
                    cal.set(Calendar.HOUR, hour);
                    cal.set(Calendar.MINUTE, minute);
                    tp.setStartDate(cal.getTime());
                    if (availableTvProgramMap.get(tmpId) != null) {
                        availableTvProgramMap.get(tmpId).setEndDate(
                                cal.getTime());
                    }
                }
                tmpId = tp.getId();
                availableTvProgramMap.put(tp.getId(), tp);
            }
        }
        if (reInitTempDataFile) {
            System.out.println("persist program data to local temp file");
            XMLEncoder xe = new XMLEncoder(new BufferedOutputStream(
                    new FileOutputStream(TEMPDATAFILE)));
            xe.writeObject(availableTvProgramMap);
            xe.close();
        }
    }

    public void deleteTempDataFromLocal() {
        System.out.println("TvProgramManager.deleteTempDataFromLocal start...");
        File file = new File(TEMPDATAFILE);
        if (file.exists()) {
            file.delete();
        }
        System.out.println("TvProgramManager.deleteTempDataFromLocal end");
    }

    public Collection getAvailableTvStationCollection() {
        return availableTvStationMap.values();
    }

    public Map<Integer, String> getAvailableTvChannelMap() {
        return new HashMap<Integer, String>(availableTvChannelMap);
    }

    public Map<Integer, String> getFavoriteTvChannelMap() {
        return new HashMap<Integer, String>(favoriteTvChannelMap);
    }

    public void setUserFavoriteTvChannelIdSet(Set<Integer> idSet) {
        userFavoriteTvChannelIdSet = idSet;
        favoriteTvChannelMap.clear();
        for (int tvChannelId : userFavoriteTvChannelIdSet) {
            favoriteTvChannelMap
                    .put(tvChannelId, tvChannelMap.get(tvChannelId));
        }
        try {
            XMLEncoder xe = new XMLEncoder(new BufferedOutputStream(
                    new FileOutputStream(FAVORITEFILE)));
            xe.writeObject(userFavoriteTvChannelIdSet);
            xe.close();
        } catch (Exception e) {
            e.printStackTrace();
            this.deleteFavoriteFromLocal();
        }
    }

    public Collection getAvailableTvProgramCollection() {
        return availableTvProgramMap.values();
    }

    public static void main(String[] args) {
        TvProgramManager tpm = new TvProgramManager();
        tpm.initTvProgram(tpm.getAvailableTvChannelMap(), false, false);
        // tpm.persistBasicDataToLocal();
        // tpm.readBasicDataFromLocal();
        System.out.println("");
    }

}
